/*                          UX-Framework                               
 *                                                                 
 *  iZE Co.,Ltd. Copyright 2009 All rights reserved.          
 *  This file is distributed under the terms of the GNU Lesser 
 *  General Public License, described in file LICENSE.                                     
 */
package jp.ize.ux;

// {{{ imports
import jp.ize.ux.UXInteraction;
import jp.ize.ux.UXObject;
import jp.ize.ux.events.UXEvent;
import jp.ize.ux.events.UXMouseEvent;
import jp.ize.ux.events.UXKeyboardEvent;
import jp.ize.ux.events.UXFocusEvent;
import jp.ize.ux.components.UXComponentResource;

import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.KeyboardEvent;
import flash.events.FocusEvent;
// }}}
/**
 * UXControllerクラス<br>
 * ユーザーの操作イベントを発生させる対象と相互作用であるUXInteractionを結びつける、UX-Frameworkの根幹を成す
 * クラス(の一つ)です。
 * UXInteractionsを、識別名がキーとなるHashで管理し、それぞれのUXInteractionが指定するイベントを受け取って、
 * UXInteractionのdoWorkを実行します。<br>
 *
 * @author		iZE Co., Ltd.<br>
 * @version		$Id$<br>
 */
class UXController<S> extends UXObject
{
	// {{{ properties

	/** 登録される子要素の一覧です */
	public var uxchildren:Array<UXObject>;
	/** このコントローラが管理するインタラクションのHashです */
	public var inters : Hash<UXInteraction<S>>;
	/** 状態オブジェクトを保持します */
 	public var state : S;

	// }}}
	// {{{ public function new()
	/**
	 * コンストラクタ。
	 */
	public function new( s : S )
	{
		super();
 		state = s;
		inters = new Hash();
		uxchildren = new Array();
	}
	// }}}
	// {{{ public function addInteraction( inter : UXInteraction<S> ) : Void
	/**
	 * 新しくインタラクションを追加します。
	 * 管理しているすべての子UXObjectに対して、指定されたインタラクションが起こるリスナーを追加します。
	 */
	public function addInteraction( inter : UXInteraction<S> ) : Void
	{
		//just sample
		var me = this;
		inters.set(inter.name, inter);
		inter.ctrl = this;
		for(etype in inter.getEvents()) {
			for ( c in uxchildren ) {
				c.addUXEventListener(etype,receive);
			}
		}
	}
	// }}}
	// {{{ public function removeInteraction( name:String ) : Void
	/**
	 * インタラクションを削除します。
	 * 管理しているすべての子UXObjectに対して、指定されたインタラクションを解除します。
	 */
	public function removeInteraction( name:String ) : Void
	{
		if ( !inters.exists(name) ) return;
		var inter = inters.get(name);
		var etypeMap:Hash<Bool> = new Hash();
		for(etype in inter.getEvents()) {
			etypeMap.set(etype,true);
		}
		for (i in inters) {
			for ( etype in i.getEvents() ) {
				etypeMap.remove(etype);
			}
		}
		for( etype in etypeMap.keys() ) {
			for ( c in uxchildren ) {
				c.removeUXEventListener(etype,receive);
			}
		}
		inters.remove(inter.name);
	}
	// }}}
	// {{{ public function replaceInteraction( inter : UXInteraction<S> ) : Void
	/**
	 * インタラクションを指定されたものに置き換えます。
	 *
	 */
	public function replaceInteraction( inter : UXInteraction<S> ) : Void
	{
		removeInteraction( inter.name );
		addInteraction( inter );
	}
	// }}}
	// {{{ public function getInteraction( intername : String ) : UXInteraction<S>
	/**
	 * 識別名internameを持つインタラクションを返します。
	 * 存在しなかった場合はnullを返します。
	 */
	public function getInteraction( intername : String ) : UXInteraction<S>
	{
		return inters.get(intername);
	}
	// }}}
	// {{{ public function addUXChild( c : UXObject ) : Void
	/**
	 * 指定されたUXObjectを管理下に追加します。Hashに登録されているすべてのインタラクションが指定された
	 * UXObjectに登録されます。
	 */
	public override function addUXChild( c : UXObject ) : Void
	{
		//just sample.
		//super.addUXChild(c);
		var me = this;
		uxchildren.push( c );
		for (inter in inters) {
			for(etype in inter.getEvents()) {
				c.addUXEventListener(etype,receive);
			}
		}
		
	}
	// }}}
	// {{{ public function removeUXChild( c : UXObject ) : Void
	/**
	 * 指定されたUXObjectを管理から外します。指定されたUXObjectのイベントリスナーを解除してします。
	 */
	public override function removeUXChild( c : UXObject ) : Void
	{
		uxchildren.remove(c);
	}
	// }}}
	// {{{ public function addUXEvent( etype:String ) : Void
	/**
	* 監視するイベント名を追加します
	*/
	public function addUXEvent( etype:String ) : Void
	{
		for ( c in uxchildren ) {
			c.addUXEventListener(etype,receive);
		}
	}

	// }}}
	// {{{ public function removeUXEvent( etype:String ) : Void
	/**
	* 指定されたイベント名のイベントを監視するのを止めます
	*/
	public function removeUXEvent( etype:String ) : Void
	{
		var flag:Bool = true;
		for (i in inters) {
			for ( et in i.getEvents() ) {
				if ( et==etype ) {
					flag = false;
				}
			}
		}
		if ( flag ) {
			for ( c in uxchildren ) {
				c.removeUXEventListener(etype,receive);
			}
		}
	}

	// }}}
	// {{{ public function trigger( intername:String, ?o:Dynamic ) : Void
	/**
	 * インタラクションを手動で発動します。
	 * o は、eventTarget です。
	 */
	public function trigger( intername:String, ?o:Dynamic ) : Void
	{
		if ( inters.exists(intername) ) {
			var inter = inters.get(intername);
			Reflect.setField(state,"eventTarget",o);
			inter.doWork(state);
		}
	}
	// }}}
	// {{{ public function triggerChain( chain:UXInteractionChain ) : Void
	/**
	* 連続するインタラクションを発動します。
	*/
	public function triggerChain( chain:UXInteractionChain ) : Void
	{
		for ( c in chain.iterator() ) {
			trigger(c);
		}
	}
	// }}}
	// {{{ public function receive( event : Event ) : Void
	/**
	* 監視しているイベントが発生したときに実行されるリスナーです。
	*/
	public function receive( event : Event ) : Void
	{
		for( intr in inters ) {
			for ( e in intr.getEvents()) {
				if (e == event.type) {
					if ( Std.is(event.target,UXObject) ) {
						Reflect.setField(state,"eventTarget",event.target);
					} else {
						if ( Std.is(event.target.parent,UXObject) ) {
							var t:Dynamic = event.target.parent;
							while ( Std.is(t,UXComponentResource) ) {
								t = t.parent;
							}
							Reflect.setField(state,"eventTarget",t);
						}
					}
					// {{{ event translation
					switch event.type {
						// {{{ mouse event
						case UXMouseEvent.DOWN :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.OVER :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.CLICK :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.DOUBLE_CLICK :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.DOWN :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.UP :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.MOVE :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.OUT :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.OVER :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.WHEEL :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.ROLL_OUT :
							Reflect.setField(state,"mouse",event);
						case UXMouseEvent.ROLL_OVER :
							Reflect.setField(state,"mouse",event);
						// }}}
						// {{{ keyboard event
						case UXKeyboardEvent.KEY_DOWN :
							Reflect.setField(state,"keyboard",event);
						case UXKeyboardEvent.KEY_UP :
							Reflect.setField(state,"keyboard",event);
						// }}}
						// {{{ focus event
						case UXFocusEvent.GOT :
							Reflect.setField(state,"focus",event);
						case UXFocusEvent.LOST :
							Reflect.setField(state,"focus",event);
						case UXFocusEvent.BY_KEY :
							Reflect.setField(state,"focus",event);
						case UXFocusEvent.BY_MOUSE :
							Reflect.setField(state,"focus",event);
						// }}}
						default:
							// just just sample.
					}
					// }}}
					intr.doWork(state);
				}
			}
		}
	}

	// }}}
}
